package com.woniuxy.secondkill.controller;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author zhangyong
 * @Date 2021/8/10 0010上午 10:48
 */
@RestController
public class KillController {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    //setnx key key存在

    // @GetMapping("/kill")
    public boolean kill() {
        //同步锁
        synchronized (KillController.class) {
            //1.读取库存
            Integer num = (Integer) redisTemplate.opsForValue().get("num");
            //2.判断库存
            if (num > 0) {
                num--;
                System.out.println("删减库存成功，还剩" + num);
                //3.修改redis中的数据
                redisTemplate.opsForValue().set("num", num);
                //
                return true;
            }
            //没库存了
            return false;
        }
    }

    /**
     *
     */
    //@GetMapping("/kill")
    public boolean kill2() {
        boolean flag = false;
        String key = "lock";//锁
        String uuid = UUID.randomUUID().toString();
        //setIfAbsent 方法底层调用的setnx指令    设置key的时候把过期时间也一并设置，原子性
        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, uuid, 10, TimeUnit.SECONDS);
        //设置过期时间
        //redisTemplate.expire(key,10, TimeUnit.SECONDS);
        if (!result) {
            return flag;
        }
        try {
            //获得锁
            Integer num = (Integer) redisTemplate.opsForValue().get("num");
            //2.判断库存
            if (num > 0) {
                num--;
                System.out.println("删减库存成功，还剩" + num);
                //3.修改redis中的数据
                redisTemplate.opsForValue().set("num", num);
                //
                flag = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁   当前线程可能会删掉其他线程的key
            if (uuid.equals(redisTemplate.opsForValue().get(key))) {
                //说明key是自己获得的
                redisTemplate.delete(key);//删掉key就释放了
            }

        }

        return flag;
    }

    /**
     * 使用redisson的分布式锁
     */

    @Resource
    private Redisson redisson;

    @GetMapping("/kill")
    public boolean kill3() {
        boolean flag = false;
        //key
        String key = "lock";
        //获取锁   setnx   默认key的过期时间10秒   自动续命也是10秒
        RLock lock = redisson.getLock(key);

        try {
            //上锁
            lock.lock();
            //处理业务
            Integer num = (Integer) redisTemplate.opsForValue().get("num");
            //2.判断库存
            if (num > 0) {
                num--;
                System.out.println("删减库存成功，还剩" + num);
                //3.修改redis中的数据
                redisTemplate.opsForValue().set("num", num);
                //
                flag = true;
            }

        } finally {
            //释放锁
            lock.unlock();
        }


        return false;
    }
}
